/**
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2009，所有权利保留。
 * 
 * 项目名：	rumba-widget2
 * 文件名：	RTimeBox.java
 * 模块说明：	
 * 修改历史：
 * Feb 12, 2009 - lxm - 创建。
 */
package com.hd123.rumba.gwt.widget2.client.form;

import java.util.Date;

import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.ui.TextBox;
import com.hd123.rumba.gwt.util.client.RDateUtil;
import com.hd123.rumba.gwt.widget2.client.fielddef.DateFieldDef;
import com.hd123.rumba.gwt.widget2.client.fielddef.FieldDef;

/**
 * 时间输入框
 * <p>
 * 
 * <b>控件元素结构</b><br>
 * div@super<br>
 * ..label@super<br>
 * ..div class=field@super<br>
 * ....input type=text class=input<br>
 * ....[? class=buttons]@super<br>
 * ....[div class=suffix]@super<br>
 * ....[? class=tip]@super<br>
 * ....[div class=note]@super
 * <p>
 * 
 * <b>CSS Style Rules</b> <ol type=disc>
 * <li>.rb-TimeBox { div }</li>
 * <li>.rb-TimeBox-disabled { div }</li>
 * <li>.rb-TimeBox .input {}</li>
 * <li>.rb-TimeBox .input-disabled { 当不可用状态时的输入框 }</li>
 * <li>.rb-TimeBox .input-readonly { 当只读状态时的输入框 }</li>
 * <li>.rb-TimeBox .input-focused { 当获得焦点状态时的输入框 }</li>
 * <li>.rb-TimeBox .input-error { 当提示错误时的输入框 }</li>
 * <li>.rb-TimeBox .input-warning { 当提示警告时的输入框 }</li>
 * <li>.rb-TimeBox .buttons {  }</li>
 * <li>.rb-TimeBox .suffix { div }</li>
 * <li>.rb-TimeBox .note {  }</li> </ol>
 * 
 * @author lxm
 * 
 */
public class RTimeBox extends RTextBoxBase {

  private static final String STYLENAME_DEFAULT = "rb-TimeBox";

  public RTimeBox() {
    super(new RTextInput());
    ((TextBox) getInput()).setMaxLength(8);
    messages = new Messages();
    setStyleName(STYLENAME_DEFAULT);
    Handler handler = new Handler();
    addKeyPressHandler(handler);
    addBlurHandler(handler);
  }

  /**
   * @param fieldDef
   *          字段定义
   */
  public RTimeBox(FieldDef fieldDef) {
    this();
    setFieldDef(fieldDef);
  }

  private Date value;
  private Date maxValue;
  private Date minValue;
  private DateTimeFormat format = DateTimeFormat.getFormat("H:mm:ss");
  private Messages messages;

  /** 当前取值，当输入值非法时为null。 */
  public Date getValue() {
    return value;
  }

  public void setValue(Date value) {
    this.value = value == null ? null : RDateUtil.timePart(value);
    if (this.value == null)
      setText("");
    else
      setText(format.format(this.value));
  }

  /**
   * 清除输入值
   * 
   */
  public void clearValue() {
    setValue(null);
  }

  /** 最大值。null表示不约束最大值。 */
  public Date getMaxValue() {
    return maxValue;
  }

  public void setMaxValue(Date maxValue) {
    this.maxValue = maxValue == null ? null : RDateUtil.timePart(maxValue);
  }

  /** 最小值。null表示不约束最小值。 */
  public Date getMinValue() {
    return minValue;
  }

  public void setMinValue(Date minValue) {
    this.minValue = minValue == null ? null : RDateUtil.timePart(minValue);
  }

  /** 日期格式。不允许为null，默认为"H:mm:ss"。 */
  public DateTimeFormat getFormat() {
    return format;
  }

  public void setFormat(DateTimeFormat format) {
    this.format = format == null ? DateTimeFormat.getFormat("H:mm:ss") : format;
  }

  /** 提示信息 */
  public Messages getMessages() {
    return messages;
  }

  public void setFieldDef(FieldDef fieldDef) {
    super.setFieldDef(fieldDef);

    if (fieldDef instanceof DateFieldDef) {
      setFormat(((DateFieldDef) fieldDef).getFormat());
    }
  }

  protected void onValidate() {
    super.onValidate();

    String inputText = getText();
    if ("".equals(inputText))
      return;

    Date newValue;
    try {
      newValue = RDateUtil.timePart(format.parse(inputText));
    } catch (Exception e) {
      getTip().addError(getTipPrefix() + messages.getInvalidText());
      return;
    }

    if (maxValue != null)
      if (newValue.after(maxValue))
        getTip().addError(getTipPrefix() + messages.getMaxText());
    if (minValue != null)
      if (newValue.before(minValue))
        getTip().addError(getTipPrefix() + messages.getMinText());
  }

  protected boolean beforeInputChange() {
    boolean result = super.beforeInputChange();
    if (result) {
      try {
        String s = getText();
        Date d = format.parse(s);
        value = RDateUtil.timePart(d);
      } catch (Exception e) {
        value = null;
      }
    } else {
      value = null;
    }
    return result;
  }

  /**
   * 提示信息
   * 
   * @author lxm
   * 
   */
  private class Messages {

    private String invalidText = "输入的不是合法的时间。";
    private String maxText;
    private String minText;

    /** 当输入的不是一个合法的时间的时候，显示的提示信息。默认为“输入的不是合法的时间。” */
    public String getInvalidText() {
      return invalidText;
    }

    public void setInvalidText(String invalidText) {
      this.invalidText = invalidText;
    }

    /** 当输入大于最大值时显示的信息，默认为“输入时间大于最大时间{0}。” */
    public String getMaxText() {
      if (maxText != null)
        return maxText;
      return "输入时间大于最大时间\"" + format.format(maxValue) + "\"。";
    }

    public void setMaxText(String maxText) {
      this.maxText = maxText;
    }

    /** 当输入小于最大值时显示的信息，默认为“输入时间小于最小时间{0}。” */
    public String getMinText() {
      if (minText != null)
        return minText;
      return "输入时间小于最小时间\"" + format.format(minValue) + "\"。";
    }

    public void setMinText(String minText) {
      this.minText = minText;
    }
  }

  /**
   * 自身的事件处理
   * 
   * @author LiQi
   * 
   */
  private class Handler implements KeyPressHandler, BlurHandler {

    private static final String BASE_CHARACTER = "0123456789:";

    public void onKeyPress(KeyPressEvent event) {
      int charCode = event.getCharCode();
      if (charCode == KeyCodes.KEY_LEFT || charCode == KeyCodes.KEY_RIGHT
          || charCode == KeyCodes.KEY_UP || charCode == KeyCodes.KEY_DOWN
          || charCode == KeyCodes.KEY_ENTER || charCode == KeyCodes.KEY_TAB
          || charCode == KeyCodes.KEY_BACKSPACE)
        return;

      // 如果是DIGIT_CHARACTER以外的键，直接取消。
      if (BASE_CHARACTER.indexOf(charCode) < 0) {
        event.preventDefault();
        return;
      }
    }

    public void onBlur(BlurEvent event) {
      if (!isValid())
        return;

      // 格式化显示
      if (value != null)
        setText(format.format(value));
    }
  }
}
